#include "plcnew.h"

#include "plc.h"
#include "decompress.h"
#include "video.h"

extern PLCindex ArtLoadCues[];
plc_buffer_index v_plc_buffer[0x10];
extern word *vRam;

#define LONGTOWORD HIWORD
#define HIWORD LEFTRADIXLONG
#define LOWORD RIGHTRADIXLONG
#define LEFTRADIXLONG(val) ((val & 0xFFFF0000) >> 16)                          //for fixed point numbers (grabs integer portion)
#define RIGHTRADIXLONG(val) (val & 0x0000FFFF)                                 //for fixed point numbers (grabs fractional portion)

/*; ---------------------------------------------------------------------------
; Subroutines to load pattern load cues

; input:
;	d0 = pattern load cue number
; ---------------------------------------------------------------------------

; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
*/

//AddPLC:
void AddPLC(word index)
{
    //movem.l	a1-a2,-(sp)

    //lea	(ArtLoadCues).l,a1
    //add.w	d0,d0
    //move.w	(a1,d0.w),d0
    //lea	(a1,d0.w),a1	; jump to relevant PLC
    PLCindex *curPLCGroup = &ArtLoadCues[index];

    //lea	(v_plc_buffer).w,a2 ; PLC buffer space
    plc_buffer_index *v_plc_bufferPtr = &v_plc_buffer[0];   

    //@findspace:
    //tst.l	(a2)		; is space available in RAM?
    //beq.s	@copytoRAM	; if yes, branch
    //addq.w	#6,a2		; if not, try next space
    //bra.s	@findspace
    while (v_plc_bufferPtr->val1 != 0) { v_plc_bufferPtr++; }
 

    //; ===========================================================================

    //@copytoRAM:
    //move.w	(a1)+,d0	; get length of PLC
    signed short length = curPLCGroup->length;

    //bmi.s	@skip
    if (length >= 0)
    {
        //@loop:
        for (int grpIndex = 0;length >= 0; length--,grpIndex++)
        {
	    //move.l	(a1)+,(a2)+
            v_plc_bufferPtr->val1 = curPLCGroup->plc[grpIndex].graphics;

	    //move.w	(a1)+,(a2)+	; copy PLC to RAM
            v_plc_bufferPtr->val2 = curPLCGroup->plc[grpIndex].vram;

            v_plc_bufferPtr++;
	    //dbf	d0,@loop	; repeat for length of PLC
        }
	
    }   
    
    //@skip:
    //movem.l	(sp)+,a1-a2
    //rts	
}   //; End of function AddPLC


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//NewPLC:
void NewPLC(word index)
{
    //movem.l	a1-a2,-(sp)

    //lea	(ArtLoadCues).l,a1
    //add.w	d0,d0
    //move.w	(a1,d0.w),d0
    //lea	(a1,d0.w),a1	; jump to relevant PLC
    PLCindex *curPLCGroup = &ArtLoadCues[index];
    
    //bsr.s	ClearPLC	; erase any data in PLC buffer space
    ClearPLC();
	
    //lea	(v_plc_buffer).w,a2
    plc_buffer_index *v_plc_bufferPtr = &v_plc_buffer[0];

    //move.w	(a1)+,d0	; get length of PLC
    signed short length = curPLCGroup->length;

    //bmi.s	@skip
    if (length >= 0)
    {
        //@loop:
        for (int grpIndex = 0;length >= 0; length--,grpIndex++)
        {
	    //move.l	(a1)+,(a2)+
            v_plc_bufferPtr->val1 = curPLCGroup->plc[grpIndex].graphics;

	    //move.w	(a1)+,(a2)+	; copy PLC to RAM
            v_plc_bufferPtr->val2 = curPLCGroup->plc[grpIndex].vram;

            v_plc_bufferPtr++;
	    //dbf	d0,@loop	; repeat for length of PLC
        }
	
    }   
  
    //@skip:
    //movem.l	(sp)+,a1-a2
    //rts
}   //; End of function NewPLC

/*; ---------------------------------------------------------------------------
; Subroutine to	clear the pattern load cues
; ---------------------------------------------------------------------------

; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
*/

//ClearPLC:				; XREF: NewPLC
void ClearPLC()
{
    //lea	(v_plc_buffer).w,a2 ; PLC buffer space in RAM
    long *buffer = (long*)&v_plc_buffer[0];

    //moveq	#$1F,d0
    long bufferLen = 0x1F;

    //@loop:
    //clr.l	(a2)+
    for (;bufferLen>=0; bufferLen--)
        *(buffer++) = 0;
    
    //dbf	d0,@loop
    //rts	
}   //; End of function ClearPLC

/*; ---------------------------------------------------------------------------
; Subroutine to	use graphics listed in a pattern load cue
; ---------------------------------------------------------------------------

; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||
*/

//RunPLC:					; XREF: GM_Level; et al
void RunPLC()
{
    //tst.l	(v_plc_buffer).w
    //beq.s	Rplc_Exit
    //tst.w	(f_plc_execute).w
    //bne.s	Rplc_Exit
    if (v_plc_buffer[0].val1 != 0 /*&& f_plc_execute == 0*/)
    {
        //movea.l	(v_plc_buffer).w,a0
        byte *gfx = v_plc_buffer[0].val1;

        //DON'T DECOMPRESS IN PARTS [not like: PART1 HERE, PART2 DURING VBLANK], DO IT ALL AT ONCE (LIKE IN LATTER HALF OF QUICKPLC)
        NemDec(gfx,(byte*)&vRam[v_plc_buffer[0].val2]);
 
        //ALSO THE QUEUE SHOULD SHIFT BACK AFTER EXECUTION/DECOMPRESSION (WHERE IT NORMALLY ALSO OCCURS AFTER DECOMPRESSION finishes DURING VBLANK)
        //OTHERWISE THE SAME PLC WILL EXECUTE OVER AND OVER
        //loc_16DC:				; XREF: sub_165E
	//lea	(v_plc_buffer).w,a0
	//moveq	#$15,d0
        long count=15;
        long index;

        //loc_16E2:				; XREF: sub_165E
	//move.l	6(a0),(a0)+
	//dbf	d0,loc_16E2
        for (index=0;count>0;count--,index++)
        {
            v_plc_buffer[index].val1=v_plc_buffer[index+1].val1;
            v_plc_buffer[index].val2=v_plc_buffer[index+1].val2;
        }
        v_plc_buffer[index++].val1=0;
        v_plc_buffer[index].val2=0;
    }
    
}   //rts	
//; End of function sub_165E

void RunAllPLCs()
{
    while(v_plc_buffer[0].val1 != 0) { RunPLC(); }
}

/*
here is code for thread/interrupt-based occurence of decompression
 
//performs initial decompression of a pattern, (determine the number of tiles for this pattern, set decompress flag so rest of decompression run during vblank, initial decompression)

        //lea	(loc_1502).l,a3
	//lea	(v_ngfx_buffer).w,a1
		
        //tests last bit in source long
        //move.w	(a0)+,d2
        word numTiles = HIWORD(gfx)

        //bpl.s	loc_160E
	//adda.w	#$A,a3

        //loc_160E:
	//andi.w	#$7FFF,d2
        //move.w	d2,(f_plc_execute).w
        f_plc_execute = upperOffset & 0x7FFF;

	//bsr.w	NemDec4
        NemDec4(v_plc_bufferPtr);

	//move.b	(a0)+,d5
	
        //asl.w	#8,d5
		move.b	(a0)+,d5
		moveq	#$10,d6
		moveq	#0,d0

		move.l	a0,(v_plc_buffer).w
		move.l	a3,(v_ptrnemcode).w
		move.l	d0,($FFFFF6E4).w
		move.l	d0,($FFFFF6E8).w
		move.l	d0,($FFFFF6EC).w
		move.l	d5,($FFFFF6F0).w
		move.l	d6,($FFFFF6F4).w

Rplc_Exit:
		rts	
; End of function RunPLC


; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

//decompression run during vblank
//for this frame, decompresses 9 next TILES in the current pattern, if any more need to be 

sub_1642:				; XREF: VBla_04; VBla_12
		tst.w	(f_plc_execute).w        //do any more tiles need to decompress for this pattern
		beq.w	locret_16DA              //if not then skip

		move.w	#9,($FFFFF6FA).w            //num. of tiles to decompress in one frame
		moveq	#0,d0                       //|
		move.w	($FFFFF684).w,d0            //vram. address to place decompressed data
		addi.w	#$120,($FFFFF684).w         //(also update address for by next frame will have aleady decompressed 9 tiles of vram data)
		bra.s	loc_1676
; End of function sub_1642


; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


sub_165E:				; XREF: Demo_Time
		tst.w	(f_plc_execute).w
		beq.s	locret_16DA
		
                move.w	#3,($FFFFF6FA).w
		moveq	#0,d0
		move.w	($FFFFF684).w,d0
		addi.w	#$60,($FFFFF684).w



loc_1676:				; XREF: sub_1642
		lea	(vdp_control_port).l,a4
		lsl.l	#2,d0
		lsr.w	#2,d0
		ori.w	#$4000,d0
		swap	d0
		move.l	d0,(a4)
		subq.w	#4,a4
		
               movea.l	(v_plc_buffer).w,a0
		movea.l	(v_ptrnemcode).w,a3
		move.l	($FFFFF6E4).w,d0
		move.l	($FFFFF6E8).w,d1
		move.l	($FFFFF6EC).w,d2
		move.l	($FFFFF6F0).w,d5
		move.l	($FFFFF6F4).w,d6
		lea	(v_ngfx_buffer).w,a1
loc_16AA:				; XREF: sub_165E
		movea.w	#8,a5
		bsr.w	NemDec3


		subq.w	#1,(f_plc_execute).w       //current tile being decompressed in pattern
		beq.s	loc_16DC                   //if all tiles have decompressed for pattern then shift queue, pattern done decompressing


                //tile counter: ex. 9 tiles per frame level mode, 3 tiles per frame demo mode
		subq.w	#1,($FFFFF6FA).w
		bne.s	loc_16AA

		move.l	a0,(v_plc_buffer).w
		move.l	a3,(v_ptrnemcode).w
		move.l	d0,($FFFFF6E4).w
		move.l	d1,($FFFFF6E8).w
		move.l	d2,($FFFFF6EC).w
		move.l	d5,($FFFFF6F0).w
		move.l	d6,($FFFFF6F4).w

locret_16DA:				; XREF: sub_1642
		rts	
; ===========================================================================

//shifts entire plc buffer back so that index 0 is now next cue (plc buffer works like stack)  
loc_16DC:				; XREF: sub_165E
		lea	(v_plc_buffer).w,a0
		moveq	#$15,d0

loc_16E2:				; XREF: sub_165E
		move.l	6(a0),(a0)+
		dbf	d0,loc_16E2
		rts	
; End of function sub_165E

; ---------------------------------------------------------------------------
; Subroutine to	execute	the pattern load cue
; ---------------------------------------------------------------------------

; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


QuickPLC:
		lea	(ArtLoadCues).l,a1 ; load the PLC index
		add.w	d0,d0
		move.w	(a1,d0.w),d0
		lea	(a1,d0.w),a1
		move.w	(a1)+,d1	; get length of PLC

	Qplc_Loop:
		movea.l	(a1)+,a0	; get art pointer
		moveq	#0,d0
		move.w	(a1)+,d0	; get VRAM address
		lsl.l	#2,d0
		lsr.w	#2,d0
		ori.w	#$4000,d0
		swap	d0
		move.l	d0,(vdp_control_port).l ; converted VRAM address to VDP format
		bsr.w	NemDec		; decompress
		dbf	d1,Qplc_Loop	; repeat for length of PLC
		rts	
; End of function QuickPLC
          */


